package cn.xy.third.alipay.service.impl;

import cn.hutool.json.JSONUtil;
import cn.xy.commons.exception.JzRuntimeException;
import cn.xy.third.alipay.bean.AliPayTransferToAccountRequestParam;
import cn.xy.third.alipay.bean.AlipayConfig;
import cn.xy.third.alipay.enums.IdentityType;
import cn.xy.third.alipay.enums.RequestSignType;
import cn.xy.third.alipay.service.AlipayService;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.alipay.easysdk.payment.wap.models.AlipayTradeWapPayResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Map;

/**
 * @author jianzheng
 */
@Slf4j
@Service
public class AlipayServiceImpl implements AlipayService {

    @Override
    public void setOptions(AlipayConfig alipayConfig) {
        try {
            Factory.setOptions(this.getOptions(alipayConfig));
        } catch (Exception e) {
            log.error("alipay init fail:", e);
        }
    }

    @Override
    public Config getOptions(AlipayConfig alipayConfig) {
        Config config = new Config();
        config.protocol = "https";
        config.gatewayHost = "openapi.alipay.com";
        config.signType = alipayConfig.getSignType();

        config.appId = alipayConfig.getAppId();
        config.merchantPrivateKey = alipayConfig.getAppPrivateKey();

        if (RequestSignType.CERT.getValue() == alipayConfig.getRequestSingType()) {
            //注：证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径，优先从文件系统中加载，加载失败后会继续尝试从CLASS_PATH中加载
            config.merchantCertPath = alipayConfig.getAppCertPath();
            config.alipayCertPath = alipayConfig.getAlipayCertPath();
            config.alipayRootCertPath = alipayConfig.getAlipayRootCertPath();
        }

        //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
        config.alipayPublicKey = alipayConfig.getAlipayPublicKey();

        config.notifyUrl = alipayConfig.getNotifyUrl();
        return config;
    }

    @Override
    public String wapUnifiedOrder(String subject, String outTradeNo, BigDecimal amount, String quitUrl, String returnUrl) {
        try {
            log.info("wapUnifiedOrder: subject[{}],outTradeNo[{}],amount[{}],quitUrl[{}],returnUrl[{}]" + subject, amount, quitUrl, returnUrl);
            AlipayTradeWapPayResponse response = Factory.Payment.Wap().pay(subject, outTradeNo, amount.toString(), quitUrl, returnUrl);
            if (ResponseChecker.success(response)) {
                log.debug("response => {}", response.body);
                return response.body;
            } else {
                log.error("webUnifiedOrder fail: {}", response.body);
            }
        } catch (Exception e) {
            log.error("web unified order fail: ", e);
        }
        return null;
    }

    @Override
    public String webUnifiedOrder(String subject, String outTradeNo, BigDecimal amount, String returnUrl) {
        try {
            log.info("webUnifiedOrder: subject[{}],outTradeNo[{}],amount[{}],returnUrl[{}]" + subject, amount, returnUrl);
            AlipayTradePagePayResponse response = Factory.Payment.Page().pay(subject, outTradeNo, amount.toString(), returnUrl);
            if (ResponseChecker.success(response)) {
                log.debug("response =>{}", response.body);
                return response.body;
            } else {
                log.error("webUnifiedOrder fail:{}", response.body);
            }
        } catch (Exception e) {
            log.error("webUnifiedOrder fail: ", e);
        }
        return null;
    }

    @Override
    public AlipayTradeRefundResponse refund(String payTradeNo, BigDecimal payTotal) {
        try {
            return Factory.Payment.Common().refund(payTradeNo, payTotal.toString());
        } catch (Exception e) {
            log.error("send refund fail:", e);
            throw new JzRuntimeException("退款失败，请稍后尝试");
        }
    }

    @Override
    public Boolean notifyVerified(Map<String, String> payNotifyMap) {
        try {
            return Factory.Payment.Common().verifyNotify(payNotifyMap);
        } catch (Exception e) {
            log.error("notify verified fail:", e);
        }
        return false;
    }

    @Override
    public String appPay(String subject, String outTradeNo, BigDecimal amount) {
        try {
            log.info("subject:" + subject);
            log.info("outTradeNo:" + outTradeNo);
            log.info("amount:" + amount);
            AlipayTradeAppPayResponse response = Factory.Payment.App().pay(subject, outTradeNo, amount.toString());
            if (ResponseChecker.success(response)) {
                log.debug("response =>{}", response.body);
                return response.body;
            } else {
                log.error("webUnifiedOrder fail:{}", response.body);
            }
        } catch (Exception e) {
            log.error("webUnifiedOrder fail: ", e);
        }
        return null;
    }

    @Override
    public AlipayClient getCertAlipayClient(AlipayConfig alipayConfig) {
        try {
            CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
            //gateway:支付宝网关（固定）https://openapi.alipay.com/gateway.do
            certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
            //APPID 即创建应用后生成,详情见创建应用并获取 APPID
            certAlipayRequest.setAppId(alipayConfig.getAppId());
            //开发者应用私钥，由开发者自己生成
            certAlipayRequest.setPrivateKey(alipayConfig.getAppPrivateKey());
            //参数返回格式，只支持 json 格式
            certAlipayRequest.setFormat("json");
            //请求和签名使用的字符编码格式，支持 GBK和 UTF-8
            certAlipayRequest.setCharset("UTF-8");
            //商户生成签名字符串所使用的签名算法类型，目前支持 RSA2 和 RSA，推荐商家使用 RSA2。
            certAlipayRequest.setSignType("RSA2");
            //应用公钥证书路径（app_cert_path 文件绝对路径）
            certAlipayRequest.setCertPath(alipayConfig.getAppCertPath());
            //支付宝公钥证书文件路径（alipay_cert_path 文件绝对路径）
            certAlipayRequest.setAlipayPublicCertPath(alipayConfig.getAlipayCertPath());
            //支付宝CA根证书文件路径（alipay_root_cert_path 文件绝对路径）
            certAlipayRequest.setRootCertPath(alipayConfig.getAlipayRootCertPath());

            // 构造client
            return new DefaultAlipayClient(certAlipayRequest);
        } catch (AlipayApiException e) {
            log.error("alipay create alipay client fail:", e);
        }
        return null;
    }

    @Override
    public AlipayFundTransUniTransferResponse getAccountRequestData(AlipayConfig alipayConfig, BigDecimal amount, String withdrawNo, String name, String account, String companyName, String desc) {
        try {
            AlipayClient alipayClient = this.getCertAlipayClient(alipayConfig);

            AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
            String content = this.getAlipayFundTransUniTransferRequestContent(amount, withdrawNo, name, account, companyName, desc);
            request.setBizContent(content);

            return alipayClient.certificateExecute(request);
        } catch (AlipayApiException e) {
            log.error("alipay fund trans uni transfer fail:", e);
        }
        return null;
    }

    @Override
    public String getAlipayFundTransUniTransferRequestContent(BigDecimal amount, String withdrawNo, String name, String account, String companyName, String desc) {
        AliPayTransferToAccountRequestParam.PayeeInfo payeeInfo = new AliPayTransferToAccountRequestParam.PayeeInfo();
        payeeInfo.setIdentity(account);
        payeeInfo.setIdentity_type(IdentityType.ALIPAY_LOGON_ID.getValue());
        payeeInfo.setName(name);

        AliPayTransferToAccountRequestParam.BusinessParams businessParams = new AliPayTransferToAccountRequestParam.BusinessParams();
        businessParams.setPayer_show_name(companyName);

        AliPayTransferToAccountRequestParam param = new AliPayTransferToAccountRequestParam();
        param.setOut_biz_no(withdrawNo);
        param.setTrans_amount(amount);
        param.setProduct_code("TRANS_ACCOUNT_NO_PWD");
        param.setBiz_scene("DIRECT_TRANSFER");
        param.setOrder_title(desc);
        param.setRemark(desc);
        param.setPayee_info(payeeInfo);
        param.setBusiness_params(JSONUtil.toJsonStr(businessParams));

        return JSONUtil.toJsonStr(param);
    }

}
